classdef DataAcquisitionModule < EquipmentControl.ZI.ziServer.ServerModules.AbstractServerModule
    %@DATAACQUISITIONMODULE �˴���ʾ�йش����ժ�?
    %   �˴���ʾ��ϸ˵��
    
    properties
        domain
        updateMode
    end
    
    methods
        function obj = DataAcquisitionModule(server, name)
            %@DATAACQUISITIONMODULE ��������ʵ��
            %   �˴���ʾ��ϸ˵��
            obj@EquipmentControl.ZI.ziServer.ServerModules.AbstractServerModule(server, name, 'dataAcquisitionModule');
        end
    end
    %%
    methods
        function initialize(obj)
            initialize@EquipmentControl.ZI.ziServer.ServerModules.AbstractServerModule(obj);
            obj.measured_data = {};
        end
        
        function obj = setFFTWindow(obj, win)
            p=inputParser;
            p.addRequired('win', @ziEnumFFTWindow.test);
            p.parse(win);
            obj.setModuleSettingValue(ziSettingsDAQModule.fft_window, win);            
        end
        
        function obj = setAverage(obj, nAverage)
            p=inputParser;
            p.addRequired('nAverage', @(x) x>0);
            p.parse(nAverage);
            obj.setModuleSettingValue(ziSettingsDAQModule.grid_repetitions, int64(nAverage));
            obj.sync(0.5);
        end   
        
        function obj = setTrigger(obj, device, trig_node, varargin)
            L = log4m.getLogger;
            p=inputParser();
            p.addRequired('device', @(x) ismember(x, obj.devices));
            p.addRequired('trig_node', @(x) isa(x, 'ziStreamNode') );
            p.addParameter('edge',         ziEnumTrigEdgeSlope.Positive, @ziEnumTrigEdgeSlope.test);
            p.addParameter('level',        0.0,                          @isnumeric);
            p.addParameter('hysteresis',   0.0,                          @isnumeric);
            p.addParameter('count',        1,                            @(x) x>0);
            p.addParameter('bits',         int64(1),                     @(x) isa(x, 'int64') );
            p.addParameter('bitmask',      int64(1),                     @(x) isa(x, 'int64') );
            p.addParameter('holdofftime',  0.0,                          @(x) x>=0.0 );
            p.addParameter('holdoffcount', 0,                            @(x) x>=0 );
            p.addParameter('delay',       -0.1,                          @isnumeric );
            p.addParameter('tSync',        0.2,                          @(x) x>=0);
            p.parse(device, trig_node, varargin{:});
            

            duration = obj.getModuleSettingValue(ziSettingsDAQModule.duration);
            delayTime = p.Results.delay * duration;
            
            if ~trig_node.isTrigNode
                error('The node [%s]is not able to be configured as a trigger node.', trig_node.toString);
            end
            
            trig_node_str = ['/' device '/' trig_node.toString];
            switch lower(trig_node.signal)
                case {'x', 'y', 'r', 'theta', 'frequency', 'auxin0', 'auxin1'}
                    obj.setModuleSettingValue(ziSettingsDAQModule.type,        1);
                    obj.setModuleSettingValue(ziSettingsDAQModule.triggernode, trig_node_str);
                    obj.setModuleSettingValue(ziSettingsDAQModule.edge,        p.Results.edge);
                    obj.setModuleSettingValue(ziSettingsDAQModule.level,       p.Results.level);
                    obj.setModuleSettingValue(ziSettingsDAQModule.hysteresis,  p.Results.hysteresis);
                    obj.setModuleSettingValue(ziSettingsDAQModule.count,       p.Results.count);
                    
                case 'dio'
                    obj.setModuleSettingValue(ziSettingsDAQModule.type,        2);
                    obj.setModuleSettingValue(ziSettingsDAQModule.triggernode, trig_node_str);
                    obj.setModuleSettingValue(ziSettingsDAQModule.edge,        p.Results.edge);
                    obj.setModuleSettingValue(ziSettingsDAQModule.bits,        p.Results.bits);
                    obj.setModuleSettingValue(ziSettingsDAQModule.bitmask,     p.Results.bitmask);
                    obj.setModuleSettingValue(ziSettingsDAQModule.count,       p.Results.count);
                    
                case {'trigdemod1phase', 'trigdemod2phase', 'trigout1', 'trigout2', 'trigin1', 'trigin2'}
                    obj.setModuleSettingValue(ziSettingsDAQModule.type,         6);
                    obj.setModuleSettingValue(ziSettingsDAQModule.triggernode,  trig_node_str);
                    obj.setModuleSettingValue(ziSettingsDAQModule.edge,         p.Results.edge);
                    obj.setModuleSettingValue(ziSettingsDAQModule.count,        p.Results.count);
            end
            
            rate = obj.enableDataTransfer(device, trig_node);
            L.info('DataAcquisitionModule::setTrigger', sprintf('Data Transfer Rate = %5.3e Sa/s', rate));
            
            obj.setModuleSettingValue(ziSettingsDAQModule.holdoff_time,  p.Results.holdofftime);
            obj.setModuleSettingValue(ziSettingsDAQModule.holdoff_count, p.Results.holdoffcount);
            obj.setModuleSettingValue(ziSettingsDAQModule.delay,         delayTime);
            obj.sync(p.Results.tSync);
        end
        
        function setUpdateMode(obj, mode)
            obj.updateMode = mode;
        end
    end
    %%
    methods        
        function res = run(obj, varargin)
            clear textprogressbar;
            
            p=inputParser;
            p.addParameter('timeout', inf, @(x) x>0);
            p.addParameter('tUpdate', 1.0, @(x) x>0);
            p.addParameter('tSync',0.2, @(x) x>=0);
            p.parse(varargin{:});        
            
            obj.sync(p.Results.tSync);
            obj.execute();            

            t0_measurement = tic; 
            textprogressbar( sprintf('%s Acquiring Data,\t', datestr(now,'yyyy-mm-dd HH:MM:SS,FFF')) ); 
            while ~obj.finished()
                textprogressbar(obj.progress()*100);
                pause(p.Results.tUpdate);
                
                if  toc(t0_measurement) > p.Results.timeout                    
                    break                   
                end
                
                obj.assembleData(obj.read(), true); %plot progress
            end
            
            if obj.finished() % normal finishing.
                textprogressbar(100); textprogressbar(' Done.');
            else % break due to timeout
                L=log4m.getLogger;
                fprintf('\n'); L.info('ScopeModule::run', sprintf('Timeout, runtime = [%3.2e]s', toc(t0_measurement)));
            end
            
            obj.assembleData(obj.read(), false); % assemble final result (without plot)
            res = EquipmentControl.ZI.ziServer.ziServerData.ziServerDaqModuleData(obj.measured_data, obj.subscribed_path, obj.domain);
            obj.finish();
        end
        
        function subscribe(obj, device, node, varargin)
            L=log4m.getLogger;
            p=inputParser;
            p.addRequired('device', @(x) ismember(x, obj.devices));
            p.addRequired('node', @(x) isa(x, 'ziStreamNode'));
            p.addOptional('group', [1, 1, 1], @(x) isnumeric(x) && length(x) == 3 && x(3)<=x(1)*x(2));
            p.addParameter('tSync',0.2, @(x) x>=0);
            p.parse(device, node, varargin{:});
            
            rate = obj.enableDataTransfer(device, node);
            L.info('DataAcquisitionModule::subscribe', sprintf('Data Transfer Rate = %5.3e Sa/s', rate));
            
            obj.subscribed_path = [obj.subscribed_path; {device, node, p.Results.group}];
            subscribe@EquipmentControl.ZI.ziServer.ServerModules.AbstractServerModule(obj, ['/' device '/' node.toString]);
            obj.sync(p.Results.tSync);
        end
    end
    
    %%
    methods(Access=private)
        function assembleData(obj, tmp, isPlot)
            if isDataAvailable(obj, tmp)
%                 switch obj.domain
                switch obj.updateMode
%                     case 'time'
                    case 'append'
                        obj.measured_data = [obj.measured_data, tmp];
%                     case 'frequency'
                    case 'replace'
                        obj.measured_data = {tmp};
                end
                
                if isPlot
                    tmpData = EquipmentControl.ZI.ziServer.ziServerData.ziServerDaqModuleData(obj.measured_data, obj.subscribed_path, obj.domain);
                    tmpData.plot_data_group(obj.monitor_hdl);
                end
            end
        end
        
        function tf = isDataAvailable(obj, tmpData)
            tf = any(cellfun(@(device, node) ziCheckPathInData(tmpData, ['/' device '/' node.toDataString]), obj.subscribed_path(:,1), obj.subscribed_path(:, 2)));
        end
    end
end

